﻿using Apache.NMS.ActiveMQ.Util;
using LD.Host;
using log4net.Core;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Documents;

namespace LD.BC
{
    [Bc(Name = "雷赛DMC1000", Brand = BrandType.DMC1000)]
    class DMC1000 : LTDmc1000, IBoardCard
    {
        private string[] sportModes = { "定长运动", "定速运动", "回零运动", "往复运动" };
        private string[] stopModes = { "减速停止", "立即停止" };
        private string[] locationModes = { "相对坐标", "绝对坐标" };
        private string[] directionModes = { "负方向", "正方向" };
        private string[] zeroModes = { "一次回零", "一次回零+反找", "两次回零", "一次回零+EZ", "EZ回零", "一次回零+反找"
        ,"原点锁存","原点+EZ锁存","EZ锁存","原点+反向EZ锁","限位一次回零","限位回零反找","限位两次回零" };
        private string[] speedModes = { "低速回零", "高速回零" };
        private string[] pluseModes = { "脉冲/方向(上升沿)", "脉冲/方向(下降沿)", "脉冲/脉冲(上升沿)", "脉冲/脉冲(下降沿)" };

        public Dictionary<string, string[]> GetParam()
        {
            Dictionary<string, string[]> param = new Dictionary<string, string[]>
            {
                { "stopModes", stopModes },
                { "directionModes", directionModes },
                { "zeroModes", zeroModes },
                { "pluseModes", pluseModes }
            };
            return param;
        }
        private int ErrCode = 0; // 轴错误码
        private string BackZeroState = "";
        private TaskEx TaskEx = new TaskEx();

        #region 监控
        public void Start()
        {
            Log4.Info("板卡监控启动");
            TaskEx.Start(Monitor, null);
        }

        #endregion

        #region 连接
        public void Connection()
        {
            int num = d1000_board_init();
            if (num <= 0 || num > 12)
            {
                Log4.Error("板卡初始化失败,未检测到板卡,请检查驱动");
                throw new Exception("板卡初始化失败");
            }
        }

        public void Closed()
        {
            TaskEx?.Cancel();
            ErrCode = LTDmc1000.d1000_board_close();
        }
        #endregion

        #region 轴运动
        public void Stop(ushort axis)
        {
            ErrCode = d1000_decel_stop(axis);
        }
        public void StopALL()
        {
            BcFactory.Instance.Config.AxisParam.ForEach((item) =>
            {
                d1000_immediate_stop(item.AxisId);
            });
        }

        /// <summary>
        /// 等轴运行结束
        /// </summary>
        /// <param name="axis"></param>
        public void WaitAxisComplete(ushort axis)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            while (d1000_check_done(axis) == 0 && stopwatch.ElapsedMilliseconds < (30 * 1000))// 判断轴运动状态
            {
                Task.Delay(50).Wait();
            }
            stopwatch.Stop();
        }

        public void WaitAxisComplete()
        {

        }

        /// <summary>
        /// 相对移动
        /// </summary>
        /// <param name="axis"></param>
        /// <param name="ration_v"></param>
        public void Move_Ration(ushort axis, double ration_v)
        {
            if (BCAlertHelper.GetErrorQty) return;
            var moveP = BcFactory.Instance.Config.AxisParam.Where(p => p.AxisId == axis).FirstOrDefault();
            if (moveP == null)
            {
                throw new Exception("轴参数无设置");
            }
            int Myaxis, MyMin_Vel, MyMax_Vel, MyDist, Myhome_dir;
            double MyTacc;

            Myaxis = axis;                         // 轴号
            MyMin_Vel = (int)moveP.Min_val;        // 初始速度
            MyMax_Vel = (int)moveP.Max_val;        // 运动速度
            Myhome_dir = (ushort)moveP.Zero_dir;   // 回零方向
            MyTacc = (double)moveP.Tacc;           // 加速时间
            MyDist = (int)ration_v;                // 相对运动距离,其值的正负表示运动方向
            if (Myhome_dir == 0)
                MyDist = MyDist * -1;

            if (BcFactory.Instance.RunModel == StateEnum.手动模式)
                MyMax_Vel = (int)moveP.Manual_val;

            ErrCode = d1000_start_s_move(axis, MyDist, MyMin_Vel, MyMax_Vel, MyTacc); // 以S形速度曲线控制指定轴至运行速度,并以相对坐标运行一段指定距离
        }

        /// <summary>
        /// 轴移动(寸动)
        /// </summary>
        /// <param name="axis"></param>
        /// <param name="direction">方向：0/反方向，1/正方向</param>
        public void Move(ushort axis, ushort direction)
        {
            if (BCAlertHelper.GetErrorQty) return;
            var moveP = BcFactory.Instance.Config.AxisParam.Where(p => p.AxisId == axis).FirstOrDefault();
            if (moveP == null)
            {
                throw new Exception("轴参数无设置");
            }
            int Myaxis, MyMin_Vel, MyMax_Vel;
            double MyTacc;

            MyMin_Vel = (int)moveP.Min_val;        // 初始速度
            MyMax_Vel = (int)moveP.Max_val;        // 运动速度,其值的正负表示运动方向
            MyTacc = (double)moveP.Tacc;           // 加速时间

            if (BcFactory.Instance.RunModel == StateEnum.手动模式)
                MyMax_Vel = (int)moveP.Manual_val;

            if (direction == 0)
                MyMax_Vel = MyMax_Vel * -1;

            ErrCode = d1000_start_sv_move(axis, MyMin_Vel, MyMax_Vel, MyTacc);        // 以S形速度曲线控制指定轴至运行速度,并以运行速度连续运行
        }

        /// <summary>
        /// 回零
        /// </summary>
        /// <param name="axis"></param>
        public void Move_BackZero(ushort axis)
        {
            if (BCAlertHelper.GetErrorQty) return;
            var moveP = BcFactory.Instance.Config.AxisParam.Where(p => p.AxisId == axis).FirstOrDefault();
            if (moveP == null)
            {
                throw new Exception("轴参数无设置");
            }
            int Myaxis, MyMin_Vel, MyMax_Vel, Myhome_dir;
            double MyTacc;
            MyMin_Vel = (int)moveP.Min_val;        // 初始速度
            MyMax_Vel = (int)moveP.Zero_val;        // 运动速度,其值的正负表示运动方向
            MyTacc = (double)moveP.Tacc;           // 加速时间
            Myhome_dir = (ushort)moveP.Zero_dir;   // 回零方向
            if (Myhome_dir == 0)
                MyMax_Vel = MyMax_Vel * -1;

            ErrCode = d1000_home_move(axis, MyMin_Vel, MyMax_Vel, MyTacc);           // 启动指定轴进行回原点运动
            //if (ErrCode == 0)
            //    BackZeroState = "回原点中";
            while (d1000_check_done(axis) == 0) //等待回原点动作完成
            {
                BackZeroState = "回原点中";
                Task.Delay(100).Wait();
            }
            if (d1000_check_done(axis) == 4)
            {
                BackZeroState = "回原点完成";
                d1000_set_command_pos(axis, 0); //将当前第 0 轴位置清零，即设为第 0 轴原点位置
            }
            else
            {
                BackZeroState = "回原点失败";
            }
        }

        /// <summary>
        /// 回零成功否
        /// </summary>
        /// <param name="axis"></param>
        /// <returns></returns>
        public bool GetHomeStatus(ushort axis)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 坐标（绝对）移动_梯形
        /// </summary>
        /// <param name="axis">轴</param>
        /// <param name="location">坐标</param>
        public void Move_Location(ushort axis, double location)
        {
            if (BCAlertHelper.GetErrorQty) return;

            var moveP = BcFactory.Instance.Config.AxisParam.Where(p => p.AxisId == axis).FirstOrDefault();
            if (moveP == null)
            {
                throw new Exception("轴参数无设置");
            }
            int MyDist, MyMin_Vel, MyMax_Vel, Myhome_dir;
            double MyTacc;

            MyDist = (int)location;                // 绝对运动位置,单位:pulse
            MyMin_Vel = (int)moveP.Min_val;        // 初始速度
            MyMax_Vel = (int)moveP.Max_val;        // 运动速度,其值的正负表示运动方向
            MyTacc = (double)moveP.Tacc;           // 加速时间

            if (BcFactory.Instance.RunModel == StateEnum.手动模式)
                MyMax_Vel = (int)moveP.Manual_val;

            Myhome_dir = moveP.Zero_dir;           // 运动方向
            if (Myhome_dir == 0)
                MyMax_Vel = MyMax_Vel * -1;

            ErrCode = d1000_start_ta_move(axis, MyDist, MyMin_Vel, MyMax_Vel, MyTacc);
        }

        /// <summary>
        /// 定量（相对）移动
        /// </summary>
        /// <param name="axis">轴</param>
        /// <param name="direction">方向：0/反方向，1/正方向</param>
        /// <param name="ration_v">定量值</param>
        public void Move_Ration(ushort axis, ushort direction, double ration_v)
        {
            if (BCAlertHelper.GetErrorQty) return;

            var moveP = BcFactory.Instance.Config.AxisParam.Where(p => p.AxisId == axis).FirstOrDefault();
            if (moveP == null)
            {
                throw new Exception("轴参数无设置");
            }
            int MyDist, MyMin_Vel, MyMax_Vel, Myhome_dir;
            double MyTacc;

            MyDist = (int)ration_v;                // 相对运动距离,其值的正负表示运动方向
            MyMin_Vel = (int)moveP.Min_val;        // 初始速度
            MyMax_Vel = (int)moveP.Max_val;        // 运动速度
            MyTacc = (double)moveP.Tacc;           // 加速时间

            if (BcFactory.Instance.RunModel == StateEnum.手动模式)
                MyMax_Vel = (int)moveP.Manual_val;

            Myhome_dir = direction;           // 运动方向
            if (Myhome_dir == 0)
                MyDist = MyDist * -1;

            ErrCode = d1000_start_t_move(axis, MyDist, MyMin_Vel, MyMax_Vel, MyTacc);
        }
        #endregion

        #region 轴参数
        /// <summary>
        /// 设置轴参数
        /// </summary>
        /// <param name="axis"></param>
        /// <param name="model"></param>
        public void SetAxisParam(ushort axis, TB_AxisParam model)
        {

        }

        public string GetAxisStatus(ushort cardNo, ushort axis)
        {
            int bit = d1000_check_done(axis);
            return bit.ToString();
        }

        /// <summary>
        /// 读取指令位置计数器值
        /// </summary>
        /// <param name="axis"></param>
        /// <returns></returns>
        public double GetAxisPosition(ushort axis)
        {
            double pos = 0;
            pos = d1000_get_command_pos(axis);
            return pos;
        }
        /// <summary>
        /// 设置指令位置计数器值
        /// </summary>
        /// <param name="axis"></param>
        /// <param name="position"></param>
        public void SetAxisPosition(ushort axis, int position)
        {
            d1000_set_command_pos(axis, position);
        }

        /// <summary>
        /// 设置使能
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="isEnabled"></param>
        public void SetSevon(ushort axisId, bool isEnabled)
        {
            throw new Exception("无设置使能函数");
        }
        public void SetSevonAll(bool enabled)
        {
            foreach (var item in BcFactory.Instance.Config.AxisParam)
            {
                SetSevon((ushort)item.AxisId, enabled);
            }
        }
        /// <summary>
        /// 导入config文档
        /// </summary>
        /// <param name="fileName"></param>
        public void LoadConfig(string fileName)
        {
            throw new Exception("配置文档导入失败，无相关函数");
        }
        /// <summary>
        /// 设置正负限位
        /// </summary>
        /// <param name="cardNo">板卡</param>
        /// <param name="axis">轴</param>
        /// <param name="n_limit">负限位</param>
        /// <param name="p_limit">正限位</param>
        public void SetSoftLimit(ushort cardNo, ushort axis, int n_limit, int p_limit)
        {
            throw new Exception("无相关函数");
        }
        /// <summary>
        /// 设置脉冲当量
        /// </summary>
        /// <param name="cardNo">板卡</param>
        /// <param name="axis">轴</param>
        /// <param name="equiv">脉冲量</param>
        public void SetEquiv(dynamic cardNo, ushort axis, double equiv)
        {
            throw new Exception("无相关函数");
        }
        /// <summary>
        /// 获取脉冲当量
        /// </summary>
        /// <param name="cardNo"></param>
        /// <param name="axis"></param>
        /// <returns></returns>
        public double GetEquiv(ushort cardNo, ushort axis)
        {
            throw new Exception("无相关函数");
        }
        public void SetOut(ushort outPos, ushort low_high)
        {
            d1000_out_bit(outPos, low_high);
        }
        /// <summary>
        /// 读取通用输出信号状态
        /// </summary>
        /// <param name="outPos"></param>
        /// <returns></returns>
        public int GetOut(int outPos)
        {
            return d1000_get_outbit(outPos);
        }
        public void DownAxisParam()
        {
            foreach (var item in BcFactory.Instance.Config.AxisParam)
            {
                // 设置脉冲输出模式
                d1000_set_pls_outmode(item.AxisId, item.Plus_Model);
            }
        }

        public bool IsMoving()
        {
            bool moving = false;
            foreach (var item in BcFactory.Instance.Config.AxisParam)
            {
                int i = item.AxisId;
                moving = d1000_check_done(i) == 0 ? true : false;
                if (moving)
                    return moving;
            }

            return moving;
        }
        public void ClearAlart(ushort axisId)
        {

        }

        /// <summary>
        /// 读取通用输入信号状态
        /// </summary>
        /// <param name="outPos"></param>
        /// <returns></returns>
        public int GetIn(int outPos)
        {
            return d1000_in_bit(outPos);
        }
        public List<int> GetIn()
        {
            List<int> result = new List<int>();
            int qty = 32;
            for (int i = 1; i <= qty; i++)
            {
                result.Add(d1000_in_bit(i));
            }
            return result;
        }

        public List<int> GetOut()
        {
            List<int> result = new List<int>();
            int qty = 32;
            for (int i = 1; i <= qty; i++)
            {
                result.Add(d1000_get_outbit(i));
            }
            return result;
        }
        #endregion

        #region 私有方法
        private void Monitor(object obj)
        {
            MonitorModel m_Data = new MonitorModel();
            try
            {
                #region IO
                int outQty = 27;
                int inQty = 32;
                for (int i = 0; i < inQty; i++)
                {
                    int _in = d1000_in_bit(i + 1);
                    //var bin_in1 = Convert.ToString(_in, 2).PadLeft(inQty, '0').Reversal().ToList();
                    m_Data.DI.Add(_in);
                }

                for (int i = 0; i < outQty; i++)
                {
                    int _out = d1000_get_outbit(i + 1);
                    //var bin_out = Convert.ToString(_out, 2).PadLeft(outQty, '0').Reversal().ToList();
                    m_Data.DO.Add(_out);
                }
                #endregion

                foreach (var item in BcFactory.Instance.Config.AxisParam)
                {
                    ushort id = item.AxisId;

                    #region 轴状态
                    int axisState = d1000_check_done(id);
                    string axisStateName = "";
                    switch (axisState)
                    {
                        case 0:
                            axisStateName = "正在运行";
                            break;
                        case 1:
                            axisStateName = "脉冲输出完毕停止";
                            break;
                        case 2:
                            axisStateName = "指令停止";
                            break;
                        case 3:
                            axisStateName = "遇限位停止";
                            break;
                        case 4:
                            axisStateName = "遇原点停止";
                            break;
                        default:
                            break;
                    }
                    string errState = "";
                    switch (ErrCode)
                    {
                        case 0:
                            errState = "成功";
                            break;
                        case 1:
                            errState = "卡号参数设置错误";
                            break;
                        case 2:
                            errState = "轴号参数设置错误";
                            break;
                        case 3:
                            errState = "其他参数设置错误";
                            break;
                    }
                    //var bin_axis = Convert.ToString(axisState, 2).PadLeft(12, '0').Reversal().ToList();

                    var io = d1000_get_axis_status(id);
                    var ios = Convert.ToString(io, 2).PadLeft(8, '0').Reversal().ToList();
                    m_Data.AxisState.Add(id, new AxisStatus()
                    {
                        //报警 = Convert.ToInt32(bin_axis[0].ToString()),
                        正限位 = Convert.ToInt32(ios[1].ToString()),
                        负限位 = Convert.ToInt32(ios[0].ToString()),
                        原点 = Convert.ToInt32(ios[2].ToString()),
                        //使能 = dmc_read_sevon_pin(_bcId, id),
                        位置 = GetAxisPosition(id),
                        运动状态 = axisStateName,
                        轴错误码 = errState,
                        回零结果 = BackZeroState,
                        停止原因 = axisStateName
                    });
                    #endregion
                }
                PubSub.Hub.Default.PublishAsync(m_Data);
            }
            catch (Exception ex)
            {
                Log4.Error($"【板卡监控】{ex.Message}", ex);
            }
        }
        /// <summary>
        /// <see cref="GetAlm(int)"/>
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public AlmModel GetAlm(ushort axisId)
        {
            AlmModel model = new AlmModel();
            ushort stop = 0;
            ushort enable = 0;
            ushort val = 0;
            //dmc_get_alm_mode(_bcId, axisId, ref enable, ref val, ref stop);
            model.ALM使能 = enable;
            model.ALM电平 = val;
            return model;
        }
        /// <summary>
        /// <see cref="SetAlm(ushort, ushort, ushort)"/>
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="enable"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int SetAlm(ushort axisId, ushort enable, ushort val)
        {
            return 0;
            //return dmc_set_alm_mode(_bcId, axisId, enable, val, 0);
        }

        public void SetAxisPosition(ushort axis, double position)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}
